package com.the_last.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.the_last.constant.ReservationConstant;
import com.the_last.mapper.ReservationMapper;
import com.the_last.mapper.ReservationTimeSlotMapper;
import com.the_last.pojo.dto.ReservationDTO;
import com.the_last.pojo.po.Reservation;
import com.the_last.pojo.po.ReservationTimeSlot;
import com.the_last.pojo.vo.PageVO;
import com.the_last.pojo.vo.ReservationTimeSlotInfo;
import com.the_last.pojo.vo.ReservationVO;
import com.the_last.service.ReservationService;
import com.the_last.service.ReservationTimeoutMessageService;
import com.the_last.utils.Result;
import com.the_last.utils.SnowflakeIdWorker;
import com.the_last.utils.TimeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class ReservationServiceImpl extends ServiceImpl<ReservationMapper, Reservation>
        implements ReservationService {
    
    private final RedissonClient redissonClient;
    private final ReservationTimeSlotMapper timeSlotMapper;
    private final ReservationTimeSlotMapper reservationTimeSlotMapper;
    private final SnowflakeIdWorker snowflakeIdWorker;
    private final ReservationTimeoutMessageService reservationTimeoutMessageService;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> createReservation(ReservationDTO reservationDTO, Long userId) {
        // 参数校验
        if (userId == null || reservationDTO.getVenueId() == null
                || reservationDTO.getDate() == null || CollectionUtils.isEmpty(reservationDTO.getTimeSlotIds())) {
            return Result.fail("参数不完整");
        }
        
        // 检查时间段连续性
        List<Integer> timeSlotIds = new ArrayList<>(reservationDTO.getTimeSlotIds());
        Collections.sort(timeSlotIds);
        for (int i = 1; i < timeSlotIds.size(); i++) {
            if (timeSlotIds.get(i) - timeSlotIds.get(i - 1) != 1) {
                return Result.fail("所选时间段必须连续");
            }
        }
        
        // 构建锁的key
        String lockKey = "reservation:lock:" + reservationDTO.getVenueId() + ":" + reservationDTO.getDate();
        RLock lock = redissonClient.getLock(lockKey);
        
        try {
            // 尝试获取锁，等待5秒，持有锁30秒
            if (!lock.tryLock(5, 30, TimeUnit.SECONDS)) {
                return Result.fail("系统繁忙，请稍后重试");
            }
            
            // 检查时间段是否已被预约
            // 获取该场馆当天所有已预约的时间段
            List<Integer> occupiedTimeSlots = reservationTimeSlotMapper.getOccupiedTimeSlots(
                    reservationDTO.getVenueId(),
                    reservationDTO.getDate()
            );
            
            boolean hasConflict = timeSlotIds.stream()
                    .anyMatch(occupiedTimeSlots::contains);
            
            if (hasConflict) {
                return Result.fail("所选时间段已被预约");
            }
            
            Date reservationDate = TimeUtil.dateFormat.parse(reservationDTO.getDate());
            
            // 创建预约记录
            long reservationId = snowflakeIdWorker.nextId();
            Reservation reservation = new Reservation();
            reservation.setId(reservationId);
            reservation.setUserId(userId);
            reservation.setVenueId(reservationDTO.getVenueId());
            reservation.setReservationDate(reservationDate);
            reservation.setApplyTime(new Date());
            reservation.setStatus(ReservationConstant.STATUS_PENDING);
            this.save(reservation);
            
            // 创建预约时间段关联记录
            List<ReservationTimeSlot> timeSlots = new ArrayList<>();
            for (Integer timeSlotId : timeSlotIds) {
                ReservationTimeSlot timeSlot = new ReservationTimeSlot();
                timeSlot.setReservationId(reservationId);
                timeSlot.setTimeSlotId(timeSlotId);
                timeSlots.add(timeSlot);
            }
            timeSlotMapper.insertBatch(timeSlots);
            
            // 发送预约超时延迟消息
            try {
                // 获取最大的时间段ID（因为时间段是连续的，最大的就是结束时间段）
                Integer maxTimeSlotId = Collections.max(timeSlotIds);
                reservationTimeoutMessageService.sendReservationTimeoutMessage(reservation, maxTimeSlotId);
                log.info("预约超时消息发送成功，预约ID: {}", reservationId);
            } catch (Exception e) {
                log.error("发送预约超时消息失败，预约ID: {}", reservationId, e);
                // 消息发送失败不影响预约创建，只记录错误日志
            }
            
            return Result.success("预约成功");
        } catch (Exception e) {
            return Result.fail("预约失败：" + e.getMessage());
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    
    @Override
    public Result<?> getReservationList(Integer venueId, String date, Integer status, Long userId, boolean needPaging, Integer pageNum, Integer pageSize) {
        try {
            List<ReservationVO> reservations;
            long total = 0;
            boolean hasMore = false;
            
            // 第一步：查询预约基本信息
            if (needPaging) {
                Page<ReservationVO> page = new Page<>(pageNum, pageSize);
                IPage<ReservationVO> result = baseMapper.selectReservationList(venueId, date, status, userId, page);
                reservations = result.getRecords();
                total = result.getTotal();
                hasMore = pageNum < result.getPages();
            } else {
                reservations = baseMapper.selectReservationList(venueId, date, status, userId);
            }
            
            if (!reservations.isEmpty()) {
                // 第二步：批量查询时间段信息
                List<String> reservationIds = reservations.stream()
                        .map(ReservationVO::getId)
                        .collect(Collectors.toList());
                
                List<ReservationTimeSlotInfo> timeSlotInfos = baseMapper.selectTimeSlotInfo(reservationIds);
                
                // 将时间段信息设置到预约对象中
                Map<Long, ReservationTimeSlotInfo> timeSlotMap = timeSlotInfos.stream()
                        .collect(Collectors.toMap(
                                ReservationTimeSlotInfo::getReservationId,
                                info -> info
                        ));
                
                reservations.forEach(reservation -> {
                    ReservationTimeSlotInfo info = timeSlotMap.get(Long.valueOf(reservation.getId()));
                    if (info != null) {
                        reservation.setTimeSlotId(info.getTimeSlotIds().split(","));
                        reservation.setStartTime(TimeUtil.timeFormat
                                .format(info.getStartTime()).substring(0, 5));
                        reservation.setEndTime(TimeUtil.timeFormat
                                .format(info.getEndTime()).substring(0, 5));
                    }
                });
            }
            
            if (needPaging) {
                PageVO<ReservationVO> pageVO = new PageVO<>();
                pageVO.setRecords(reservations);
                pageVO.setTotal(total);
                pageVO.setHasMore(hasMore);
                return Result.success(pageVO);
            } else {
                return Result.success(reservations);
            }
        } catch (Exception e) {
            log.error("获取预约列表失败", e);
            return Result.fail("获取预约列表失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result deleteReservation(Long id) {
        if (id == null) {
            return Result.fail("预约ID不能为空");
        }
        
        try {
            // 获取预约信息
            Reservation reservation = this.getById(id);
            if (reservation == null) {
                return Result.fail("预约不存在");
            }
            
            // 删除预约时间段关联
            reservationTimeSlotMapper.delete(
                    Wrappers.<ReservationTimeSlot>lambdaQuery()
                            .eq(ReservationTimeSlot::getReservationId, id)
            );
            
            // 删除预约
            this.removeById(id);
            
            return Result.success("删除成功");
        } catch (Exception e) {
            log.error("删除预约失败", e);
            return Result.fail("删除预约失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateReservationStatus(Long id, Integer status) {
        if (id == null || status == null) {
            return Result.fail("参数不完整");
        }
        
        // 验证状态值
        if (status < 0 || status > 2) {
            return Result.fail("无效的状态值");
        }
        
        try {
            // 获取预约信息
            Reservation reservation = this.getById(id);
            if (reservation == null) {
                return Result.fail("预约不存在");
            }
            
            // 检查状态变更的合法性
            if (!isValidStatusChange(reservation.getStatus(), status)) {
                return Result.fail("不允许的状态变更");
            }
            
            // 更新状态
            reservation.setStatus(status);
            this.updateById(reservation);
            
            return Result.success("状态更新成功");
        } catch (Exception e) {
            log.error("更新预约状态失败", e);
            return Result.fail("更新预约状态失败：" + e.getMessage());
        }
    }
    
    /**
     * 检查状态变更是否合法
     * 规则：
     * 1. 待使用(1) -> 已取消(0)或已使用(2)
     * 2. 其他状态不允许变更
     */
    private boolean isValidStatusChange(Integer currentStatus, Integer newStatus) {
        if (ReservationConstant.STATUS_PENDING.equals(currentStatus)) {
            return ReservationConstant.STATUS_CANCELLED.equals(newStatus) ||
                   ReservationConstant.STATUS_USED.equals(newStatus);
        }
        return false;
    }
    
    
    @Override
    public boolean hasActiveReservations(Integer venueId) {
        if (venueId == null) {
            return false;
        }
        
        try {
            // 获取当前日期和时间
            Date now = new Date();
            String currentDate = TimeUtil.dateFormat.format(now);
            String currentTime = TimeUtil.timeFormat.format(now);
            
            // 查询有效的预约（排除已取消和已超时的状态）
            Long count = baseMapper.selectCount(
                    Wrappers.<Reservation>lambdaQuery()
                            .eq(Reservation::getVenueId, venueId)
                            .ne(Reservation::getStatus, ReservationConstant.STATUS_CANCELLED)
                            .ne(Reservation::getStatus, ReservationConstant.STATUS_TIMEOUT)
                            .and(wrapper -> wrapper
                                    .gt(Reservation::getReservationDate, currentDate)
                                    .or(orWrapper -> orWrapper
                                            .eq(Reservation::getReservationDate, currentDate)
                                            .exists("SELECT 1 FROM reservation_time_slot rts " +
                                                    "JOIN time_slot ts ON rts.time_slot_id = ts.id " +
                                                    "WHERE rts.reservation_id = reservation.id " +
                                                    "AND ts.end_time > '" + currentTime + "'")
                                    )
                            )
            );
            
            return count > 0;
        } catch (Exception e) {
            log.error("检查场馆未完成预约失败", e);
            return false;
        }
    }
}